package com.computer.network.security;

import com.computer.network.security.filter.CheckTokenFilter;
import com.computer.network.security.filter.CustomFilter;
import com.computer.network.security.filter.MenuAccessDecisionManager;
import com.computer.network.security.handler.AnonymousAuthenticationHandler;
import com.computer.network.security.handler.CustomerAccessDeniedHandler;
import com.computer.network.security.handler.LoginFailureHandler;
import com.computer.network.security.handler.LoginSuccessHandler;
import com.computer.network.service.AuthorityService;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 配置登录认证流程
 */
@Component
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private AnonymousAuthenticationHandler anonymousAuthenticationHandler;
    @Resource
    private CustomerAccessDeniedHandler customerAccessDeniedHandler;
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
    @Resource
    private CheckTokenFilter checkTokenFilter;
    @Resource
    private MenuAccessDecisionManager menuAccessDecisionManager;
    @Resource
    private CustomFilter customFilter;

    /**
     * security自带加密类
     * 易错：（框架默认用户名密码区分大小写，需手动设置用户名和密码）
     *
     * @return
     */
    @Bean
    private BCryptPasswordEncoder encryptionPassWord() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录前验证有无token
        http.addFilterBefore(checkTokenFilter, UsernamePasswordAuthenticationFilter.class).
                //登录流程
                        formLogin(). //开启登录验证
                loginProcessingUrl("/api/user/login"). //登录请求
                usernameParameter("userName").passwordParameter("password").//设置用户名密码的字段名称
                successHandler(loginSuccessHandler). //成功处理器
                failureHandler(loginFailureHandler). //失败处理器
                and().csrf().disable(). //关闭csrf检查
                sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and(). //关闭创建session提交，改为token提交
                authorizeRequests()
                .antMatchers("/login","/logout")
                .permitAll()
                //除上面，所有请求都需要认证
                .anyRequest()
                .authenticated()
                //设置自定义规则
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setAccessDecisionManager(menuAccessDecisionManager);
                        o.setSecurityMetadataSource(customFilter);
                        return o;
                    }
                }).and().
                //其他请求都拦截
                        exceptionHandling(). //异常处理器
                authenticationEntryPoint(anonymousAuthenticationHandler). //匿名用户无权限处理器
                accessDeniedHandler(customerAccessDeniedHandler). //认证用户无权限处理器
                and().cors(); //开启跨域请求
    }

    /**
     * 验证用户名，密码
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customerUserDetailsService).passwordEncoder(encryptionPassWord());
    }
}
